<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./assets/global.css" />
    <link
      rel="stylesheet"
      href="./assets/highlight/styles/github-dark.min.css"
    />
    <script src="./assets/highlight/highlight.min.js"></script>
    <!--引入代码高亮js-->

    <style>
      .container {
        display: flex;
        flex-wrap: wrap;
        padding: 20px;
      }

      .container canvas {
        margin-right: 20px;
        border: 1px dashed salmon;
      }

      pre {
        margin: 0;
      }
    </style>
  </head>

  <body>
    <script type="module">
      import {
        Maths,
        Randoms,
        Animation,
        v2,
        Vector2,
      } from "https://gcore.jsdelivr.net/npm/@3r/tool/index.js";

      /**
       * 创建画布
       * @typedef {Object} IRenderParam
       * @property {HTMLCanvasElement} IRenderParam.canvas
       * @property {CanvasRenderingContext2D} IRenderParam.context
       *
       *
       * @param {Object} params
       * @param {number} params.width - 画布宽度
       * @param {number} params.height - 画布高度
       * @param {(param:IRenderParam)=>void} params.render - 渲染方法
       */
      function createCanvas({ width, height, render }) {
        const container = document.createElement("div");
        const canvasContainer = document.createElement("div");
        const canvas = document.createElement("canvas");
        const codeContainer = document.createElement("div");
        const codePre = document.createElement("pre");
        const code = document.createElement("code");

        canvas.width = width;
        canvas.height = height;
        const context = canvas.getContext("2d");

        container.classList.add("container");
        codeContainer.classList.add("code");
        code.classList.add("hljs", "language-html");

        codePre.appendChild(code);
        codeContainer.appendChild(codePre);
        canvasContainer.appendChild(canvas);
        container.appendChild(canvasContainer);
        container.appendChild(codeContainer);

        let codeTextContent = render.toString();
        codeTextContent = codeTextContent.split("\n");
        let codeStartLine = codeTextContent.findIndex((line) =>
          line.includes("//")
        );
        codeTextContent = codeTextContent.slice(
          codeStartLine,
          codeTextContent.length - 1
        );
        codeTextContent = codeTextContent.map((line) =>
          line.replace("                ", "")
        );
        codeTextContent = codeTextContent.join("\n");
        code.textContent = codeTextContent;
        document.body.appendChild(container);
        render({
          canvas: canvas,
          context,
        });
      }

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // lineCap 属性
          context.beginPath();
          context.moveTo(20, 20);
          context.lineTo(180, 20);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.lineCap = "butt"; // 默认
          context.stroke();

          context.beginPath();
          context.moveTo(20, 70);
          context.lineTo(180, 70);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.lineCap = "round"; // 圆
          context.stroke();

          context.beginPath();
          context.moveTo(20, 120);
          context.lineTo(180, 120);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.lineCap = "square"; // 方
          context.stroke();

          context.beginPath();
          context.moveTo(20, 170);
          context.lineTo(180, 170);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.lineCap = "square"; // 方
          context.closePath(); // 会使lineCap不生效
          context.stroke();

          // 辅助观察线
          context.beginPath();
          context.moveTo(20, 0);
          context.lineTo(20, 300);
          context.moveTo(180, 0);
          context.lineTo(180, 300);
          context.strokeStyle = "red";
          context.lineWidth = 1;
          context.lineCap = "butt"; // 默认
          context.stroke();

          // 矩形一角未封口问题
          context.beginPath();
          context.moveTo(20, 200);
          context.lineTo(80, 200);
          context.lineTo(80, 260);
          context.lineTo(20, 260);
          context.lineTo(20, 200);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          // 两种方式任选其一
          // context.lineCap = 'square'
          // context.closePath();
          context.stroke();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // lineJoin 属性
          context.beginPath();
          context.moveTo(20, 20);
          context.lineTo(180, 20);
          context.lineTo(20, 50);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.closePath();
          context.lineJoin = "miter"; // 默认
          context.stroke();

          context.beginPath();
          context.moveTo(20, 70);
          context.lineTo(180, 70);
          context.lineTo(20, 100);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.closePath();
          context.lineJoin = "bevel";
          context.stroke();

          context.beginPath();
          context.moveTo(20, 120);
          context.lineTo(180, 120);
          context.lineTo(20, 150);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.closePath();
          context.lineJoin = "round";
          context.stroke();

          context.beginPath();
          context.moveTo(20, 170);
          context.lineTo(180, 170);
          context.lineTo(20, 200);
          context.strokeStyle = "blue";
          context.lineWidth = 10;
          context.closePath();
          context.lineJoin = "miter"; // 默认
          context.miterLimit = "1"; // 如果斜接长度超过 miterLimit 的值，边角会以 lineJoin 的 "bevel" 类型来显示。
          context.stroke();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 绘制星星⭐
          function drawStar(x, y, R, r, color) {
            // let R = 100
            // let r = 40
            context.beginPath();
            for (let i = 0; i < 5; i++) {
              // 外角
              context.lineTo(
                R * Math.cos(((18 + i * 72) / 180) * Math.PI) + x,
                -R * Math.sin(((18 + i * 72) / 180) * Math.PI) + y
              );
              // 内角
              context.lineTo(
                r * Math.cos(((54 + i * 72) / 180) * Math.PI) + x,
                -r * Math.sin(((54 + i * 72) / 180) * Math.PI) + y
              );
            }
            context.fillStyle = color;
            context.closePath();
            context.fill();
          }

          drawStar(150, 150, 100, 40, "yellow");
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // translate 移动画布
          context.beginPath();
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#f0f";
          context.closePath();
          context.fill();

          context.beginPath();
          context.translate(50, 50);
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#f0f";
          context.closePath();
          context.fill();

          context.beginPath();
          context.translate(50, 50); // 叠加性
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#f0f";
          context.closePath();
          context.fill();

          // 盖住第一个
          context.beginPath();
          context.translate(-100, -100); // 叠加性
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#ff0";
          context.closePath();
          context.fill();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // save restore 保存和恢复画布
          context.beginPath();
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#f0f";
          context.closePath();
          context.fill();

          context.save();
          context.beginPath();
          context.translate(50, 50);
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#f0f";
          context.closePath();
          context.fill();
          context.restore();

          // 盖住第二个
          context.save();
          context.beginPath();
          context.translate(50, 50); // 叠加性
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#0ff";
          context.closePath();
          context.fill();
          context.restore();

          // 盖住第一个
          context.save();
          context.beginPath();
          context.moveTo(50, 50);
          context.lineTo(120, 50);
          context.lineTo(120, 120);
          context.lineTo(50, 120);
          context.fillStyle = "#ff0";
          context.closePath();
          context.fill();
          context.restore();

          // 绘制星星⭐
          function drawStar(x, y, R, r, color) {
            // let R = 100
            // let r = 40
            context.save();
            context.translate(x, y);
            context.beginPath();
            for (let i = 0; i < 5; i++) {
              // 外角
              context.lineTo(
                R * Math.cos(((18 + i * 72) / 180) * Math.PI),
                -R * Math.sin(((18 + i * 72) / 180) * Math.PI)
              );
              // 内角
              context.lineTo(
                r * Math.cos(((54 + i * 72) / 180) * Math.PI),
                -r * Math.sin(((54 + i * 72) / 180) * Math.PI)
              );
            }
            context.fillStyle = color;
            context.closePath();
            context.fill();
            context.restore();
          }

          drawStar(150, 150, 100, 40, "yellow");
          drawStar(170, 170, 100, 40, "red");
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // rotate 默认绕(0，0)旋转
          context.save();
          context.rotate((30 / 180) * Math.PI);
          context.strokeStyle = "red";
          context.strokeRect(100, 100, 100, 50);
          context.restore();

          context.save();
          context.rotate((-30 / 180) * Math.PI);
          context.strokeStyle = "red";
          context.strokeRect(100, 100, 100, 50);
          context.restore();

          // scale 整个画布放大
          context.save();
          context.scale(2, 2);
          context.strokeStyle = "red";
          context.lineWidth = 1;
          context.strokeRect(50, 50, 100, 50);
          context.restore();

          // 绘制星星⭐
          function drawStar(x, y, R, r, a, s, color) {
            // let R = 100
            // let r = 40
            context.save();
            context.translate(x, y);
            context.scale(s, s);
            context.rotate((a / 180) * Math.PI);
            context.beginPath();
            for (let i = 0; i < 5; i++) {
              // 外角
              context.lineTo(
                R * Math.cos(((18 + i * 72) / 180) * Math.PI),
                -R * Math.sin(((18 + i * 72) / 180) * Math.PI)
              );
              // 内角
              context.lineTo(
                r * Math.cos(((54 + i * 72) / 180) * Math.PI),
                -r * Math.sin(((54 + i * 72) / 180) * Math.PI)
              );
            }
            context.fillStyle = color;
            context.closePath();
            context.fill();
            context.restore();
          }
          drawStar(100, 100, 120, 50, 40, 1.2, "red");
        },
      });
      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 绘制星空

          // 绘制星星⭐
          function drawStar(x, y, R, r, a, s, color) {
            // let R = 100
            // let r = 40
            context.save();
            context.translate(x, y);
            context.scale(s, s);
            context.rotate((a / 180) * Math.PI);
            context.beginPath();
            for (let i = 0; i < 5; i++) {
              // 外角
              context.lineTo(
                R * Math.cos(((18 + i * 72) / 180) * Math.PI),
                -R * Math.sin(((18 + i * 72) / 180) * Math.PI)
              );
              // 内角
              context.lineTo(
                r * Math.cos(((54 + i * 72) / 180) * Math.PI),
                -r * Math.sin(((54 + i * 72) / 180) * Math.PI)
              );
            }
            context.fillStyle = color;
            context.closePath();
            context.fill();
            context.restore();
          }
          context.fillStyle = "#000";
          context.fillRect(0, 0, canvas.width, canvas.height);
          for (let i = 0; i < 50; i++) {
            let x = Randoms.getRandomInt(0, canvas.width);
            let y = Randoms.getRandomInt(0, canvas.height);
            let a = Randoms.getRandomInt(0, 180);
            drawStar(x, y, 30, 15, a, 1, "yellow");
          }
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // arcTo 绘制曲线

          // 封装带有辅助线的arcTo方法
          function drawArcTo(x1, y1, x2, y2, radius) {
            context.beginPath();
            context.moveTo(x1 - x2, y1);
            context.arcTo(...arguments);
            context.strokeStyle = "red";
            context.stroke();

            context.beginPath();
            context.moveTo(x1 - x2, y1);
            context.lineTo(x1, y1);
            context.lineTo(x2, y2);
            context.strokeStyle = "#808080";
            context.stroke();
          }

          drawArcTo(200, 100, 200, 200, 50);
          drawArcTo(240, 70, 200, 200, 50);
          drawArcTo(180, 140, 200, 200, 50);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 绘制月亮
          let a = v2(40, 10);
          let b = v2(40, 70);
          let c = v2(120, 40);

          let R = (Vector2.distance(a, c) * 3) / 8;
          context.moveTo(a.x, a.y);
          context.arcTo(c.x, c.y, b.x, b.y, R);
          // 只能逆时针绘制
          context.arc(40, 40, 30, (1 / 2) * Math.PI, (3 / 2) * Math.PI, true);
          context.fillStyle = "yellow";
          context.fill();
          function drawMoon(a, b, c, color) {
            let R = (Vector2.distance(a, c) * 3) / 8;
            context.beginPath();
            context.moveTo(a.x, a.y);
            context.arcTo(c.x, c.y, b.x, b.y, R);
            // 只能逆时针绘制
            context.arc(
              a.x,
              (b.y - a.y) / 2 + a.y,
              (b.y - a.y) / 2,
              (1 / 2) * Math.PI,
              (3 / 2) * Math.PI,
              true
            );
            context.fillStyle = color;
            context.fill();
          }

          drawMoon(
            a.plus(v2(100, 0)),
            b.plus(v2(100, 0)),
            c.plus(v2(100, 0)),
            "red"
          );
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 绘制月亮 贝塞尔二次曲线
          let a = v2(40, 10);
          let b = v2(40, 70);
          let c = v2(120, 40);

          let R = (Vector2.distance(a, c) * 3) / 8;
          context.moveTo(a.x, a.y);
          context.arcTo(c.x, c.y, b.x, b.y, R);
          // 只能逆时针绘制
          context.arc(40, 40, 30, (1 / 2) * Math.PI, (3 / 2) * Math.PI, true);
          context.fillStyle = "yellow";
          context.fill();
          function drawMoon(a, b, c, color) {
            context.beginPath();
            context.moveTo(a.x, a.y);
            context.quadraticCurveTo(c.x, c.y, b.x, b.y);
            // 只能逆时针绘制
            context.arc(
              a.x,
              (b.y - a.y) / 2 + a.y,
              (b.y - a.y) / 2,
              (1 / 2) * Math.PI,
              (3 / 2) * Math.PI,
              true
            );
            context.fillStyle = color;
            context.fill();
          }

          drawMoon(
            a.plus(v2(100, 0)),
            b.plus(v2(100, 0)),
            c.plus(v2(60, 0)),
            "red"
          );
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 绘制贝塞尔三次曲线
          let s = v2(10, 20);
          let a = v2(80, 10);
          let b = v2(40, 70);
          let c = v2(120, 40);

          context.beginPath();
          context.moveTo(s.x, s.y);
          context.bezierCurveTo(a.x, a.y, b.x, b.y, c.x, c.y);
          context.strokeStyle = "#f00";
          context.stroke();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 文本渲染
          context.font = "bold 20px Arial";
          context.textBaseline = "top";
          context.strokeStyle = "red";
          context.strokeText("Canvas奇幻之旅", 20, 20);
          context.fillStyle = "blue";
          context.fillText("Canvas奇幻之旅", 20, 80);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // Font属性详解
          context.textBaseline = "top";
          context.fillStyle = "blue";
          context.font = "italic normal normal 20px Arial";
          context.fillText("Canvas奇幻之旅", 20, 20);
          context.font = "oblique normal normal 20px Arial";
          context.fillText("Canvas奇幻之旅", 20, 80);
          context.font = "normal small-caps normal 20px Arial";
          context.fillText("Canvas奇幻之旅", 20, 140);
          context.font = "normal normal bold 20px Arial";
          context.fillText("Canvas奇幻之旅", 20, 200);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // textAlign
          context.textBaseline = "top";
          context.fillStyle = "blue";
          context.textAlign = "left";
          context.fillText("Canvas奇幻之旅", 150, 20);
          context.textAlign = "center";
          context.fillText("Canvas奇幻之旅", 150, 60);
          context.textAlign = "right";
          context.fillText("Canvas奇幻之旅", 150, 100);
          // textBaseLine
          context.textAlign = "center";
          context.textBaseline = "top";
          context.fillText("Canvas奇幻之旅", 150, 140);
          context.textBaseline = "middle";
          context.fillText("Canvas奇幻之旅", 150, 180);
          context.textBaseline = "bottom";
          context.fillText("Canvas奇幻之旅", 150, 220);

          // 辅助线
          context.beginPath();
          context.moveTo(150, 0);
          context.lineTo(150, 300);
          context.stroke();
          context.beginPath();
          context.moveTo(0, 140);
          context.lineTo(300, 140);
          context.stroke();
          context.beginPath();
          context.moveTo(0, 180);
          context.lineTo(300, 180);
          context.stroke();
          context.beginPath();
          context.moveTo(0, 220);
          context.lineTo(300, 220);
          context.stroke();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 文本的度量
          context.textBaseline = "top";
          context.fillStyle = "blue";
          context.font = "italic normal normal 20px Arial";
          context.fillText("Canvas奇幻之旅", 20, 20);
          let measureText = context.measureText("Canvas奇幻之旅");
          console.log(measureText.width);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 阴影效果
          context.font = "italic normal 600 20px Arial";
          context.shadowColor = "blue";
          context.shadowOffsetX = 5;
          context.shadowOffsetY = 5;
          context.shadowBlur = 2;
          context.fillText("Canvas奇幻之旅", 20, 150);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 线性渐变
          let linearGradient = context.createLinearGradient(0, 0, 150, 150);
          linearGradient.addColorStop(0, "#0aa");
          linearGradient.addColorStop(1, "#eef");
          context.fillStyle = linearGradient;
          context.fillRect(0, 0, 150, 150);
          // 径向渐变
          let radialGradient = context.createRadialGradient(
            225,
            75,
            0,
            225,
            75,
            75
          );
          radialGradient.addColorStop(0, "#f00");
          radialGradient.addColorStop(1, "#fff");
          context.fillStyle = radialGradient;
          context.fillRect(150, 0, 150, 150);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 彩虹🌈
          let linearGradient = context.createRadialGradient(
            150,
            150,
            50,
            150,
            150,
            75
          );
          linearGradient.addColorStop(0, "purple");
          linearGradient.addColorStop(0.167, "blue");
          linearGradient.addColorStop(0.334, "turquoise");
          linearGradient.addColorStop(0.501, "green");
          linearGradient.addColorStop(0.668, "yellow");
          linearGradient.addColorStop(0.835, "orange");
          linearGradient.addColorStop(1, "red");
          context.fillStyle = linearGradient;

          context.beginPath();
          context.arc(150, 150, 50, 0, Math.PI, true);
          context.arc(150, 150, 75, Math.PI, 0);
          context.closePath();
          // context.stroke();
          context.fill();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 以图片或画布作为画布背景
          let image = new Image();
          image.src = "./assets/lianliankan/mask.png";
          image.style.objectFit = "cover";
          image.onload = () => {
            let patternNo = context.createPattern(image, "no-repeat");
            context.fillStyle = patternNo;
            context.fillRect(0, 0, 150, 100);
            let patternR = context.createPattern(image, "repeat");
            context.fillStyle = patternR;
            context.fillRect(150, 0, 150, 100);

            let patternX = context.createPattern(image, "repeat-x");
            context.fillStyle = patternX;
            context.fillRect(0, 150, 150, 100);

            let patternY = context.createPattern(image, "repeat-y");
            context.fillStyle = patternY;
            context.fillRect(150, 150, 150, 100);
          };
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // clip裁剪区域
          context.beginPath();
          context.fillStyle = "#333";
          context.fillRect(0, 0, canvas.width, canvas.height);
          context.closePath();

          context.beginPath();
          context.arc(150, 150, 40, 0, Math.PI * 2);
          context.fillStyle = "#fff";
          context.closePath();
          context.fill();
          context.clip();

          context.font = "bold 40px Arial";
          context.fillStyle = "blue";
          context.fillText("Canvas奇幻之旅", 150, 150);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 探照灯
          let light = {
            x: 150,
            y: 150,
            R: 40,
            vx: 3,
            vy: 3,
          };
          let render = () => {
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.save();

            context.beginPath();
            context.fillStyle = "#333";
            context.fillRect(0, 0, canvas.width, canvas.height);
            context.closePath();
            context.beginPath();
            context.arc(light.x, light.y, light.R, 0, Math.PI * 2);
            context.fillStyle = "#fff";
            context.closePath();
            context.fill();
            context.clip();

            context.font = "bold 40px Arial";
            context.fillStyle = "blue";
            context.fillText("Canvas奇幻之旅", 150, 150);
            context.restore();
          };
          let update = () => {
            // light.x += light.vx;
            // light.y += light.vy
            // // 右
            // if (light.x + light.R >= canvas.width) {
            //     light.x = canvas.width - light.R;
            //     light.vx = -light.vx
            // }
            // // 左
            // if (light.x - light.R <= 0) {
            //     light.x = light.R;
            //     light.vx = -light.vx
            // }

            // // 下
            // if (light.y + light.R >= canvas.height) {
            //     light.y = canvas.height - light.R;
            //     light.vy = -light.vy
            // }
            // // 上
            // if (light.y - light.R <= 0) {
            //     light.y = light.R;
            //     light.vy = -light.vy
            // }

            light.R += 2;
            if (light.R >= 50) {
              light.R = 0;
            }
          };

          let run = () => {
            setInterval(() => {
              render();
              update();
            }, 20);
          };

          run();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 判断某个点是否在所构建的路径内
          context.beginPath();
          context.arc(150, 150, 75, 0, Math.PI * 2);
          context.closePath();
          context.stroke();

          let isPointInPathRes = context.isPointInPath(150, 80);
          console.log(isPointInPathRes);
          if (isPointInPathRes) {
            console.log("在圈内");
          } else {
            console.log("不在圈内");
          }

          context.fillRect(150, 80, 2, 2);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 使用isPointInPath实现鼠标交互
          canvas.addEventListener("mousedown", (ev) => {
            let x = ev.clientX - canvas.getBoundingClientRect().left;
            let y = ev.clientY - canvas.getBoundingClientRect().top;

            render(x, y);
          });

          let render = (x, y) => {
            context.clearRect(0, 0, canvas.width, canvas.height);
            // ⚪
            context.beginPath();
            context.arc(150, 150, 75, 0, Math.PI * 2);
            let isPointInPathRes = context.isPointInPath(x, y);
            if (isPointInPathRes) {
              context.fillStyle = "red";
            } else {
              context.fillStyle = "blue";
            }
            context.closePath();
            context.fill();

            // ■
            context.beginPath();
            context.moveTo(0, 0);
            context.lineTo(0, 50);
            context.lineTo(50, 50);
            context.lineTo(50, 0);
            isPointInPathRes = context.isPointInPath(x, y);
            if (isPointInPathRes) {
              context.fillStyle = "red";
            } else {
              context.fillStyle = "blue";
            }
            context.closePath();
            context.fill();

            // ▲
            context.beginPath();
            context.moveTo(300, 300);
            context.lineTo(250, 300);
            context.lineTo(300, 250);
            isPointInPathRes = context.isPointInPath(x, y);
            if (isPointInPathRes) {
              context.fillStyle = "red";
            } else {
              context.fillStyle = "blue";
            }
            context.closePath();
            context.fill();
          };

          render();
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          let cy = 75;
          // globalAlpha属性
          context.font = "bold 12px Arial";
          context.textAlign = "center";
          context.textBaseline = "top";
          context.fillText("globalAlpha", 90, cy - 70);
          context.beginPath();
          context.arc(75, cy, 60, 0, Math.PI * 2);
          context.fillStyle = "purple";
          context.globalAlpha = 0.5;
          context.closePath();
          context.fill();
          context.beginPath();
          context.arc(75 + 30, cy, 60, 0, Math.PI * 2);
          context.fillStyle = "blue";
          context.globalAlpha = 0.2;
          context.closePath();
          context.fill();

          // globalCompositeOperation属性
          let globalCompositeOperationArr = [
            "source-over", // 预设值。将新图形放在旧图形之上。
            "destination-over", // 将新图形放在旧图形之下。
            "source-in", // 只保留新、旧图片重叠的新圆形区域，其余透明。
            "destination-in", // 只保留新、旧图片重叠的新圆形区域，其余透明。
            "source-out", // 只保留新、旧图像的非重叠的新圆形区域，其余为透明。
            "destination-out", // 只保留新、旧图像的非重叠的旧圆形区域，其余为透明。
            "source-atop", // 新圆形只在绘制新、旧图像重叠的新圆形区域，然后盖在旧图形之上
            "destination-atop", // 旧图形只保留在新、旧图形重叠的旧圆形区域，然后盖在新圆形之上。
            "lighter", // 新旧图像重叠区域的颜色，有新、旧图像的颜色吗相加而得
            "xor", // 新旧图像重叠区域设为透明
            "copy", // 移除其他图像，只保留新图形
          ];

          let currentIdx = 0;

          setInterval(() => {
            context.clearRect(0, 0, canvas.width, canvas.height);
            // globalCompositeOperation属性
            context.fillStyle = "#000";
            context.globalAlpha = 1;
            let item = globalCompositeOperationArr[currentIdx];
            console.log(item);
            context.globalCompositeOperation = item;
            context.beginPath();
            context.arc(75, cy, 60, 0, Math.PI * 2);
            context.fillStyle = "purple";
            context.closePath();
            context.fill();
            context.beginPath();
            context.arc(75 + 30, cy, 60, 0, Math.PI * 2);
            context.fillStyle = "blue";
            context.closePath();
            context.fill();
            context.fillText(item, 90, cy - 70);
            currentIdx++;
            if (currentIdx >= globalCompositeOperationArr.length) {
              currentIdx = 0;
            }
          }, 2000);
        },
      });

      createCanvas({
        width: 300,
        height: 300,
        render: ({ canvas, context }) => {
          // 非零环绕规则
          var w = canvas.width,
            h = canvas.height;

          var x = w / 2,
            y = h / 2,
            r = 100,
            start = -Math.PI / 2,
            end = (Math.PI * 3) / 2;

          context.arc(x, y, r, start, end);
          context.fillStyle = "#D43D59";
          context.fill();
          context.beginPath();
          context.moveTo(x, y - r);
          // 顶点连下左
          context.lineTo(
            x - r * Math.sin(Math.PI / 5),
            y + r * Math.cos(Math.PI / 5)
          );

          // 下左连上右
          context.lineTo(
            x + r * Math.cos(Math.PI / 10),
            y - r * Math.sin(Math.PI / 10)
          );
          // 上右连上左
          context.lineTo(
            x - r * Math.cos(Math.PI / 10),
            y - r * Math.sin(Math.PI / 10)
          );
          // 上左连下右
          context.lineTo(
            x + r * Math.sin(Math.PI / 5),
            y + r * Math.cos(Math.PI / 5)
          );
          context.fillStyle = "#246AB2";
          // fill填充规则---奇偶原则
          context.fill("evenodd");
        },
      });
    </script>
  </body>
</html>
